home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 August: Tool Chest / Dev.CD Aug 94.toast / Sample Code / AppsToGo / DTS.Lib / GWLayers.c < prev    next >
Encoding:
Text File  |  1994-03-24  |  32.4 KB  |  1,175 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** Program:        DTS.Lib
  5. ** File:        GWLayers.c
  6. ** Written by:  Eric Soldan and Forrest Tanaka
  7. **
  8. ** Copyright © 1989-1993 Apple Computer, Inc.
  9. ** All rights reserved.
  10. */
  11.  
  12. /* You may incorporate this sample code into your applications without
  13. ** restriction, though the sample code has been provided "AS IS" and the
  14. ** responsibility for its operation is 100% yours.  However, what you are
  15. ** not permitted to do is to redistribute the source as "DSC Sample Code"
  16. ** after having made changes. If you're going to re-distribute the source,
  17. ** we require that you make it clear in the source that the code was
  18. ** descended from Apple Sample Code, but that you've made changes. */
  19.  
  20. /* This is an implementation of off-screen GWorld handling.  This particular
  21. ** implementation uses GWorlds in a hierarchical manner, with each layer in
  22. ** the hierarchy having its own tasks to handle at its specific level.
  23. ** The advantage to this is that it can conform to many applications.  Each
  24. ** application may need a different number of layers, and each layer may
  25. ** need to perform a different kind of operation.  By having an unlimited
  26. ** number of layers, and by having each layer handle its own application
  27. ** specific tasks, off-screen GWorld handling can be standardized.
  28. **
  29. ** A common use for off-screen stuff is to move an object around in a 
  30. ** window over a background.  To accomplish this, we need 3 layers.
  31. ** These are:
  32. **
  33. ** 1) The window layer.  This layer transfers a rectangle of pixels from
  34. **    the middle layer into the window layer, once the middle layer is ready.
  35. **    The rectangle transferred would be large enough to cover the old
  36. **    location and the new location, thus moving the piece without having
  37. **    to turn it off in the old location as a separate step.  This gives a
  38. **    very smooth appearance when moving an object.
  39. ** 2) A middle layer that is used to apply the object being moved to the
  40. **    background plus removing the object from the old location.  Once these
  41. **    two tasks are done, the off-screen work area is ready to be transferred
  42. **    to the window layer.
  43. ** 3) A background image against which the object moves.  This is used to
  44. **    restore the middle layer at the location where the object being moved
  45. **    was last at.
  46. **
  47. ** The top layer object relates to the window, and therefore we don't need an
  48. ** off-screen GWorld for it.  A call to create this layer might look like the below:
  49. **
  50. ** err = NewLayer(&windowLayer,   Layer object handle is returned here.
  51. **                nil,            Top layer, so there is no above layer.
  52. **                nil,            Uses default layer procedure.
  53. **                window,         Window used by the layer object.
  54. **                0,              Desired depth (0 for screen depth).
  55. **                0);             Custom layer init data, if any.
  56. **
  57. ** If NewLayer succeeds, the layer object handle is returned in windowLayer.
  58. ** If it fails, nil is returned in windowLayer, plus an error is returned.
  59. ** If windowLayer is successfully created, then we can proceed to create the
  60. ** next two layers.  In the case below, we are creating an off-screen layer
  61. ** that has a pixmap the same size and depth as windowLayer.  If this is
  62. ** what we want for the middle layer, then we can again use the default
  63. ** LayerProc for the kLayerInit message.  All we need to do is to call the
  64. ** default layerProc with a kLayerInit message.  We want the standard
  65. ** action for initialization, but we want our own update action.  That's
  66. ** why we have a custom layerProc for the middle layer.  The call would look
  67. ** something like the below:
  68. **
  69. ** err = NewLayer(&middleLayer,     Layer object handle is returned here.
  70. **                windowLayer,      Layer above this layer.
  71. **                MiddleLayerProc,  Custom layerProc.
  72. **                nil,              Create a pixmap for layer.
  73. **                0,                Pixmap created as same size/depth as above layer.
  74. **                0);
  75. **
  76. ** The background layer would be created similarly.  When you are finished with
  77. ** the layers, you can dispose of them one at a time with DisposeLayer, or you
  78. ** can dispose of all of them in the layer chain with DisposeThisAndBelowLayers.
  79. **
  80. ** Inserting a layer is done by position, and not by which layer it goes above
  81. ** or below.  The reason for this is that the layer positions are most likely
  82. ** absolute, and therefore it is better to indicate their position with an
  83. ** absolute number instead of always relating it to some other layer.  If it
  84. ** is necessary to insert a layer specifically above or below some other layer,
  85. ** it would be done as follows:
  86. **         InsertLayer(newLayer, aboveLayer, GetLayerPosition(aboveLayer) + 1);
  87. **         InsertLayer(newLayer, belowLayer, GetLayerPosition(belowLayer));
  88. **
  89. ** The sample applications DTS.Draw and Kibitz uses the off-screen layer code.
  90. ** For a sample usage, see the file Window2.c in DTS.Draw, or Offscreen.c in Kibitz.
  91. */
  92.  
  93.  
  94.  
  95. /*****************************************************************************/
  96.  
  97.  
  98.  
  99. #ifndef __ERRORS__
  100. #include <Errors.h>
  101. #endif
  102.  
  103. #ifndef __GESTALTEQU__
  104. #include <GestaltEqu.h>
  105. #endif
  106.  
  107. #ifndef __GWLAYERS__
  108. #include "GWLayers.h"
  109. #endif
  110.  
  111. #ifndef __RESOURCES__
  112. #include <Resources.h>
  113. #endif
  114.  
  115. #ifndef __STRINGUTILS__
  116. #include <StringUtils.h>
  117. #endif
  118.  
  119. #ifndef __WINDOWS__
  120. #include <Windows.h>
  121. #endif
  122.  
  123. #define kQDOriginal 0
  124.  
  125. static OSErr    DefaultLayerInit(LayerObj theLayer);
  126. static OSErr    DefaultLayerUpdate(LayerObj theLayer);
  127. static OSErr    DefaultLayerDispose(LayerObj theLayer);
  128.  
  129. static OSErr    MakeLayerWorld(GWorldPtr *layerWorld, LayerObj theLayer, Rect bnds);
  130. static void        KillLayerWorld(LayerObj theLayer);
  131. static void        SmartGetGWorld(CGrafPtr *port, GDHandle *gdh);
  132. static void        SmartSetGWorld(CGrafPtr port, GDHandle gdh);
  133. static short    GetQDVersion(void);
  134.  
  135.  
  136.  
  137. /*****************************************************************************/
  138. /*****************************************************************************/
  139.  
  140.  
  141.  
  142. #pragma segment GWLayers
  143. OSErr    NewLayer(LayerObj *newLayer, LayerObj aboveLayer, LayerProc theProc,
  144.                  GrafPtr basePort, short depth, unsigned long theData)
  145. {
  146.     OSErr        err;
  147.     LayerRecPtr    lptr;
  148.     CGrafPtr    scratchPort;
  149.     GDHandle    baseGDevice;
  150.  
  151.     *newLayer = (LayerObj)NewHandleClear(sizeof(LayerRec));
  152.     err = MemError();
  153.     if (err) return(err);
  154.         /* If not enough memory for layer object, return nil and error. */
  155.  
  156.     SmartGetGWorld(&scratchPort, &baseGDevice);
  157.     if (!theProc)
  158.         theProc = DefaultLayerProc;
  159.             /* If layer proc is nil, then they want the default behavior. */
  160.  
  161.     lptr = **newLayer;
  162.     lptr->layerPort     = basePort;
  163.     lptr->layerGDevice  = baseGDevice;
  164.     lptr->layerDepth    = depth;
  165.     lptr->xferMode      = srcCopy;
  166.     lptr->layerProc     = theProc;
  167.     lptr->layerData     = theData;
  168.         /* Layer object is now initialized, except for layers that need a GWorld
  169.         ** created.  This will occur when the layer proc is called with an
  170.         ** initialization message.  (All fields not explicitly set are 0.) */
  171.  
  172.     InsertLayer(*newLayer, aboveLayer, GetLayerPosition(aboveLayer) + 1);
  173.         /* Connect the layer to the layer chain.  The default initialization
  174.         ** behavior may need this, as it may create a GWorld of the same size
  175.         ** as the above layer.  If it isn't connected to the layer chain, then
  176.         ** there is no above layer. */
  177.  
  178.     err = (*theProc)(*newLayer, kLayerInit);
  179.     if (err) {
  180.         DisposeLayer(*newLayer);
  181.         *newLayer = nil;
  182.             /* There wasn't enough memory to create the off-screen GWorld, so
  183.             ** dispose of the layer object.  Since we failed, we need to return
  184.             ** nil and the error. */
  185.     }
  186.  
  187.     return(err);
  188. }
  189.  
  190.  
  191.  
  192. /*****************************************************************************/
  193.  
  194.  
  195.  
  196. #pragma segment GWLayers
  197. void    DetachLayer(LayerObj theLayer)
  198. {
  199.     LayerObj    aboveLayer, belowLayer;
  200.  
  201.     if (theLayer) {
  202.         aboveLayer = (*theLayer)->aboveLayer;
  203.         belowLayer = (*theLayer)->belowLayer;
  204.         if (aboveLayer)
  205.             (*aboveLayer)->belowLayer = belowLayer;
  206.         if (belowLayer)
  207.             (*belowLayer)->aboveLayer = aboveLayer;
  208.         (*theLayer)->aboveLayer = (*theLayer)->belowLayer = nil;
  209.     }
  210. }
  211.  
  212.  
  213.  
  214. /*****************************************************************************/
  215.  
  216.  
  217.  
  218. #pragma segment GWLayers
  219. OSErr    DisposeLayer(LayerObj theLayer)
  220. {
  221.     OSErr    err;
  222.  
  223.     err = noErr;
  224.     if (theLayer) {
  225.         err = (*((*theLayer)->layerProc))(theLayer, kLayerDispose);
  226.         DetachLayer(theLayer);
  227.         DisposeHandle((Handle)theLayer);
  228.     }
  229.  
  230.     return(err);
  231. }
  232.  
  233.  
  234.  
  235. /*****************************************************************************/
  236.  
  237.  
  238.  
  239. #pragma segment GWLayers
  240. OSErr    DisposeThisAndBelowLayers(LayerObj theLayer)
  241. {
  242.     OSErr    err, err2;
  243.  
  244.     err = noErr;
  245.     if (theLayer) {
  246.         err2 = DisposeThisAndBelowLayers((*theLayer)->belowLayer);
  247.         err  = DisposeLayer(theLayer);
  248.         if (!err)
  249.             err = err2;
  250.     }
  251.     return(err);
  252. }
  253.  
  254.  
  255.  
  256. /*****************************************************************************/
  257.  
  258.  
  259.  
  260. #pragma segment GWLayers
  261. short    GetLayerPosition(LayerObj theLayer)
  262. {
  263.     short    pos;
  264.  
  265.     if (!theLayer) return(0);
  266.  
  267.     for (pos = 0; (theLayer = (*theLayer)->aboveLayer) != nil; ++pos) {};
  268.     return(pos);
  269. }
  270.  
  271.  
  272.  
  273. /*****************************************************************************/
  274.  
  275.  
  276.  
  277. #pragma segment GWLayers
  278. LayerObj    GetTopLayer(LayerObj theLayer)
  279. {
  280.     for (; (*theLayer)->aboveLayer; theLayer = (*theLayer)->aboveLayer) {};
  281.     return(theLayer);
  282. }
  283.  
  284.  
  285.  
  286. /*****************************************************************************/
  287.  
  288.  
  289.  
  290. #pragma segment GWLayers
  291. LayerObj    GetBottomLayer(LayerObj theLayer)
  292. {
  293.     for (; (*theLayer)->belowLayer; theLayer = (*theLayer)->belowLayer) {};
  294.     return(theLayer);
  295. }
  296.  
  297.  
  298.  
  299. /*****************************************************************************/
  300.  
  301.  
  302.  
  303. #pragma segment GWLayers
  304. void    InsertLayer(LayerObj theLayer, LayerObj referenceLayer, short pos)
  305. {
  306.     LayerObj    aboveLayer, belowLayer;
  307.     short        i;
  308.  
  309.     if (theLayer) {
  310.         if (theLayer == referenceLayer) {
  311.             /* If theLayer layer is the same as referenceLayer... */
  312.  
  313.             belowLayer = (*theLayer)->belowLayer;
  314.             if (belowLayer)
  315.                 referenceLayer = belowLayer;
  316.             aboveLayer = (*theLayer)->aboveLayer;
  317.             if (aboveLayer)
  318.                 referenceLayer = aboveLayer;
  319.                     /* Try to make the reference layer not the same as theLayer.
  320.                     ** If it is the same as theLayer, then when theLayer is
  321.                     ** removed from the old hierarchy, we lose the ability to re-add
  322.                     ** it to the hierarchy in a new location. */
  323.         }
  324.  
  325.         DetachLayer(theLayer);
  326.             /* Remove layer from its old hierarchy, if any. */
  327.  
  328.         if (!referenceLayer) return;
  329.             /* If there isn't a valid alternative reference, then theLayer
  330.             ** IS the hierarchy and no action is taken. */
  331.  
  332.         aboveLayer = nil;
  333.         belowLayer = GetTopLayer(referenceLayer);
  334.             /* aboveLayer now nil.  belowLayer now is top layer.  These
  335.             ** are the correct values if the layer being added is to be
  336.             ** the new top layer.  This will be the case if pos is 0.
  337.             ** We now walk the linked list pos number of times to get the
  338.             ** correct position.  We also terminate if we reach the end
  339.             ** of the linked list, no matter what pos is.  This will allow
  340.             ** values of pos that are too big to insert the layer at the
  341.             ** end of the linked list. */
  342.  
  343.         for (i = 0; ((belowLayer) && (i != pos)); ++i) {
  344.             aboveLayer = belowLayer;
  345.             belowLayer = (*belowLayer)->belowLayer;
  346.         }
  347.             /* We now have correct values for aboveLayer and belowLayer.  Note that
  348.             ** these values may be nil, which would be correct. */
  349.         (*theLayer)->aboveLayer = aboveLayer;
  350.         if (aboveLayer)
  351.             (*aboveLayer)->belowLayer = theLayer;
  352.         (*theLayer)->belowLayer = belowLayer;
  353.         if (belowLayer)
  354.             (*belowLayer)->aboveLayer = theLayer;
  355.     }
  356. }
  357.  
  358.  
  359.  
  360. /*****************************************************************************/
  361.  
  362.  
  363.  
  364. /*****************************************************************************/
  365.  
  366.  
  367.  
  368. #pragma segment GWLayers
  369. OSErr    UpdateLayer(LayerObj theLayer)
  370. {
  371.     OSErr    err;
  372.  
  373.     err = noErr;
  374.     if (theLayer) {
  375.         err = UpdateLayer((*theLayer)->belowLayer);
  376.             /* Handle the updates from the bottom up. */
  377.         if (!err)
  378.             err = (*((*theLayer)->layerProc))(theLayer, kLayerUpdate);
  379.                 /* Chain possible errors through each level of recursion. */
  380.     }
  381.     return(err);
  382. }
  383.  
  384.  
  385.  
  386. /*****************************************************************************/
  387.  
  388.  
  389.  
  390. #pragma segment GWLayers
  391. Rect    GetEffectiveSrcRect(LayerObj theLayer)
  392. {
  393.     Rect    srcRect;
  394.  
  395.     if (!theLayer)
  396.         SetRect(&srcRect, 0, 0, 0, 0);
  397.     else {
  398.         srcRect = (*theLayer)->srcRect;
  399.         if (EmptyRect(&srcRect))
  400.             srcRect = ((*theLayer)->layerPort)->portRect;
  401.     }
  402.     return(srcRect);
  403. }
  404.  
  405.  
  406.  
  407. /*****************************************************************************/
  408.  
  409.  
  410.  
  411. #pragma segment GWLayers
  412. Rect    GetEffectiveDstRect(LayerObj theLayer)
  413. {
  414.     Rect    dstRect;
  415.  
  416.     if (!theLayer)
  417.         SetRect(&dstRect, 0, 0, 0, 0);
  418.     else {
  419.         dstRect = (*theLayer)->dstRect;
  420.         if (EmptyRect(&dstRect))
  421.             dstRect = ((*theLayer)->layerPort)->portRect;
  422.     }
  423.     return(dstRect);
  424. }
  425.  
  426.  
  427.  
  428. /*****************************************************************************/
  429.  
  430.  
  431.  
  432. #pragma segment GWLayers
  433. OSErr    DefaultLayerProc(LayerObj theLayer, short message)
  434. {
  435.     OSErr    err;
  436.  
  437.     err = noErr;
  438.     if (theLayer) {
  439.         switch (message) {        /* Dispatch to the correct default behavior. */
  440.             case kLayerInit:
  441.                 err = DefaultLayerInit(theLayer);
  442.                 break;
  443.             case kLayerDispose:
  444.                 err = DefaultLayerDispose(theLayer);
  445.                 break;
  446.             case kLayerUpdate:
  447.                 err = DefaultLayerUpdate(theLayer);
  448.                 break;
  449.             default:
  450.                 break;
  451.         }
  452.     }
  453.     return(err);
  454. }
  455.  
  456.  
  457.  
  458. /*****************************************************************************/
  459.  
  460.  
  461.  
  462. #pragma segment GWLayers
  463. Rect    UpdateUpdateRects(LayerObj theLayer)
  464. {
  465.     Rect    lastUpdate, thisUpdate, dstRect;
  466.  
  467.     if (theLayer) {
  468.         lastUpdate = (*theLayer)->lastUpdate;
  469.         (*theLayer)->lastUpdate = thisUpdate = (*theLayer)->thisUpdate;
  470.         SetRect(&((*theLayer)->thisUpdate), 0, 0, 0, 0);
  471.  
  472.         if ((*theLayer)->includeLastUpdate) {
  473.             (*theLayer)->includeLastUpdate = false;
  474.             if (EmptyRect(&lastUpdate))
  475.                 lastUpdate = thisUpdate;
  476.             if (EmptyRect(&thisUpdate))
  477.                 thisUpdate = lastUpdate;
  478.             UnionRect(&thisUpdate, &lastUpdate, &thisUpdate);
  479.                 /* We are going to update the last and current update rects.
  480.                 ** This will allow the appearance of movement for a foreground
  481.                 ** object.  The old location is cleared, plus the new location
  482.                 ** is updated. */
  483.             dstRect = GetEffectiveDstRect(theLayer);
  484.             SectRect(&thisUpdate, &dstRect, &thisUpdate);
  485.         }
  486.     }
  487.     else SetRect(&thisUpdate, 0, 0, 0, 0);
  488.  
  489.     return(thisUpdate);
  490. }
  491.  
  492.  
  493.  
  494. /*****************************************************************************/
  495.  
  496.  
  497.  
  498. #pragma segment GWLayers
  499. void    InvalLayer(LayerObj theLayer, Rect invalRect, Boolean includeLastUpdate)
  500. {
  501.     Rect        thisUpdate, srcRect, dstRect;
  502.     LayerObj    belowLayer;
  503.     short        ow, oh;
  504.     long        dw, dh, sw, sh;
  505.  
  506.     if (theLayer) {
  507.         belowLayer = (*theLayer)->belowLayer;
  508.         dstRect    = GetEffectiveDstRect(theLayer);
  509.  
  510.         SectRect(&dstRect, &invalRect, &invalRect);
  511.         if (!EmptyRect(&invalRect)) {                /* If there is something to invalidate... */
  512.             thisUpdate = (*theLayer)->thisUpdate;    /* There may be a prior unhandled update... */
  513.             if (EmptyRect(&thisUpdate))
  514.                 thisUpdate = invalRect;                /* UnionRect doesn't */
  515.             UnionRect(&thisUpdate, &invalRect, &(*theLayer)->thisUpdate);    /* like empty rects. */
  516.  
  517.             if (belowLayer) {
  518.                 /* If we have a below layer, then pass the update down.  The effectiveSrcRct
  519.                 ** rect for the below layer may be a different size than the effectiveDstRct.
  520.                 ** If this is the case, we want to scale invalRect to invalidate a proportional
  521.                 ** area in the below layer. */
  522.  
  523.                 srcRect = GetEffectiveSrcRect(belowLayer);
  524.  
  525.                 dw = dstRect.right  - dstRect.left;        /* Calculate widths and heights for */
  526.                 dh = dstRect.bottom - dstRect.top;        /* srcRect and dstRect. */
  527.                 sw = srcRect.right  - srcRect.left;
  528.                 sh = srcRect.bottom - srcRect.top;
  529.  
  530.                 OffsetRect(&invalRect, -dstRect.left, -dstRect.top);
  531.                     /* We want to align the upper-left corner of the srcRect and dstRect
  532.                     ** so that the scaling also aligns the invalRect into the correct
  533.                     ** place in the below layer's effectiveSrcRect.  invalRect is now
  534.                     ** positioned relative to a dstRect with a upper-left corner of 0,0. */
  535.  
  536.                 if (dw != sw) {        /* Width dstRect different than srcRect. */
  537.                     ow = invalRect.right  - invalRect.left;
  538.                     invalRect.left  = (short)((invalRect.left  * sw) / dw);
  539.                     invalRect.right = (short)((invalRect.right * sw) / dw);
  540.                     if ((((invalRect.right  - invalRect.left) * dw) / sw) != ow)
  541.                         ++invalRect.right;
  542.                             /* We can possibly lose a fraction of a pixel on the right edge when
  543.                             ** scaling the invalRect.  It won't hurt if we inval just a bit too
  544.                             ** much, whereas invalidating too little is a bad thing. */
  545.                 }
  546.  
  547.                 if (dh != sh) {        /* Height dstRect different than srcRect. */
  548.                     oh = invalRect.bottom - invalRect.top;
  549.                     invalRect.top    = (short)((invalRect.top    * sh) / dh);
  550.                     invalRect.bottom = (short)((invalRect.bottom * sh) / dh);
  551.                     if ((((invalRect.bottom - invalRect.top ) * dh) / sh) != oh)
  552.                         ++invalRect.bottom;
  553.                 }
  554.  
  555.                 OffsetRect(&invalRect, srcRect.left, srcRect.top);
  556.                     /* Displace the new invalRect correctly relative to the srcRect. */
  557.             }
  558.         }
  559.  
  560.         if (includeLastUpdate)
  561.             (*theLayer)->includeLastUpdate = true;
  562.                 /* If requested to update last position as well, flag it. */
  563.  
  564.         InvalLayer(belowLayer, invalRect, includeLastUpdate);
  565.             /* Invalidate the below layer with the new (possibly scaled) invalRect. */
  566.     }
  567. }
  568.  
  569.  
  570. /*****************************************************************************/
  571.  
  572.  
  573.  
  574. #pragma segment GWLayers
  575. void    SetLayerWorld(LayerObj theLayer)
  576. {
  577.     CGrafPtr    keepPort;
  578.     GDHandle    keepGDevice;
  579.  
  580.     /* This is a convenient call for setting a GWorld, while remembering what
  581.     ** the previous GWorld was.  This should be balanced with a call to
  582.     ** ResetLayerWorld.  A count of how many times this is called is kept
  583.     ** so that the old GWorld is cached only if SetLayerWorld is currently
  584.     ** in balance with ResetLayerWorld.  This keeps the oldest kept GWorld
  585.     ** from being overwritten by subsequent calls. */
  586.  
  587.     if (theLayer) {
  588.         if (!(*theLayer)->cachedCount++) {
  589.             SmartGetGWorld(&keepPort, &keepGDevice);
  590.             (*theLayer)->cachedPort    = keepPort;
  591.             (*theLayer)->cachedGDevice = keepGDevice;
  592.         }
  593.         SmartSetGWorld((CGrafPtr)(*theLayer)->layerPort, (*theLayer)->layerGDevice);
  594.         LockLayerWorld(theLayer);
  595.     }
  596. }
  597.  
  598.  
  599.  
  600. /*****************************************************************************/
  601.  
  602.  
  603.  
  604. #pragma segment GWLayers
  605. void    ResetLayerWorld(LayerObj theLayer)
  606. {
  607.     /* This is used to undo a call to SetLayerWorld.  Calls to ResetLayerWorld
  608.     ** should be balanced with previous calls to SetLayerWorld. */
  609.  
  610.     if (theLayer) {
  611.         UnlockLayerWorld(theLayer);
  612.         if (!--(*theLayer)->cachedCount)
  613.             SmartSetGWorld((*theLayer)->cachedPort, (*theLayer)->cachedGDevice);
  614.     }
  615. }
  616.  
  617.  
  618.  
  619. /*****************************************************************************/
  620.  
  621.  
  622.  
  623. #pragma segment GWLayers
  624. void    LockLayerWorld(LayerObj theLayer)
  625. {
  626.     Handle    bitmap;
  627.  
  628.     /* This is a convenient way to lock down the pixels for a layer's GWorld.
  629.     ** A locked count is kept to make sure that the GWorld is locked only the
  630.     ** first time this is called.  Calls to LockLayerWorld will most likely
  631.     ** be balanced by calls to UnlockLayerWorld, but not necessarily.  It may
  632.     ** be desirable to keep a GWorld call locked.  In this case, right after
  633.     ** creating the layer (and indirectly its GWorld), call LockLayerWorld.
  634.     ** This will initially lock it.  Subsequent calls would be balanced, and
  635.     ** therefore there will always be one more LockLayerWorld call than
  636.     ** UnlockLayerWorld calls.  This will keep it locked. */
  637.  
  638.     if (theLayer) {
  639.         if ((*theLayer)->layerOwnsPort) {
  640.             if (!(*theLayer)->lockedCount++) {
  641.                 bitmap = (*theLayer)->layerBitmap;
  642.                 if (bitmap) {
  643.                     HLock(bitmap);
  644.                     (*theLayer)->layerPort->portBits.baseAddr = *bitmap;
  645.                 }
  646.                 else
  647.                     LockPixels(GetGWorldPixMap((GWorldPtr)(*theLayer)->layerPort));
  648.             }
  649.         }
  650.     }
  651. }
  652.  
  653.  
  654.  
  655. /*****************************************************************************/
  656.  
  657.  
  658.  
  659. #pragma segment GWLayers
  660. void    UnlockLayerWorld(LayerObj theLayer)
  661. {
  662.     /* This undoes what LockLayerWorld does.  Calls to UnlockLayerWorld will
  663.     ** generally be balanced with calls to LockLayerWorld. */
  664.  
  665.     if (theLayer) {
  666.         if ((*theLayer)->layerOwnsPort) {
  667.             if (!--(*theLayer)->lockedCount) {
  668.                 if ((*theLayer)->layerBitmap)
  669.                     HUnlock((*theLayer)->layerBitmap);
  670.                 else
  671.                     UnlockPixels(GetGWorldPixMap((GWorldPtr)(*theLayer)->layerPort));
  672.             }
  673.         }
  674.     }
  675. }
  676.  
  677.  
  678.  
  679. /*****************************************************************************/
  680.  
  681.  
  682.  
  683. #pragma segment GWLayers
  684. RgnHandle    ScreenDepthRegion(short depth)
  685. {
  686.     RgnHandle        retRgn, tmpRgn;
  687.     GDHandle        device;
  688.     PixMapHandle    pmap;
  689.     Rect            rct;
  690.     GrafPtr            mainPort;
  691.  
  692.     retRgn = NewRgn();
  693.  
  694.     if (GetQDVersion() == kQDOriginal) {
  695.         if (depth == 1) {
  696.             GetWMgrPort(&mainPort);
  697.             rct = mainPort->portRect;
  698.             RectRgn(retRgn, &rct);
  699.         }
  700.     }
  701.     else {
  702.         tmpRgn = NewRgn();
  703.         for (device = GetDeviceList(); device; device = GetNextDevice(device)) {
  704.             if (
  705.                 (TestDeviceAttribute(device, screenDevice)) &&
  706.                 (TestDeviceAttribute(device, screenActive))
  707.             ) {
  708.                 pmap = (*device)->gdPMap;
  709.                 if ((*pmap)->pixelSize >= depth) {
  710.                     rct = (*device)->gdRect;
  711.                     RectRgn(tmpRgn, &rct);
  712.                     UnionRgn(retRgn, tmpRgn, retRgn);
  713.                 }
  714.             }
  715.         }
  716.         DisposeRgn(tmpRgn);
  717.     }
  718.  
  719.     return(retRgn);
  720. }
  721.  
  722.  
  723.  
  724. /*****************************************************************************/
  725.  
  726.  
  727.  
  728. #pragma segment GWLayers
  729. CIconHandle    ReadCIcon(short iconID)
  730. {
  731.     Handle    hndl;
  732.  
  733.     if (GetQDVersion() == kQDOriginal) {
  734.         hndl = GetResource('cicn', iconID);
  735.         DetachResource(hndl);
  736.         return((CIconHandle)hndl);
  737.     }
  738.  
  739.     return(GetCIcon(iconID));
  740. }
  741.  
  742.  
  743.  
  744. /*****************************************************************************/
  745.  
  746.  
  747.  
  748. #pragma segment GWLayers
  749. void    KillCIcon(CIconHandle icon)
  750. {
  751.     if (!icon) return;
  752.  
  753.     if (GetQDVersion() == kQDOriginal)
  754.         DisposeHandle((Handle)icon);
  755.     else
  756.         DisposeCIcon(icon);
  757. }
  758.  
  759.  
  760.  
  761. /*****************************************************************************/
  762.  
  763.  
  764.  
  765. #pragma segment GWLayers
  766. void    DrawCIcon(CIconHandle icon, Rect destRect)
  767. {
  768.     if (!icon) return;
  769.  
  770.     if (GetQDVersion() == kQDOriginal)
  771.         DrawCIconByDepth(icon, destRect, 1, true);
  772.     else
  773.         PlotCIcon(&destRect, icon);
  774. }
  775.  
  776.  
  777.  
  778. /*****************************************************************************/
  779.  
  780.  
  781.  
  782. #pragma segment GWLayers
  783. void    DrawCIconNoMask(CIconHandle icon, Rect destRect)
  784. {
  785.     Rect    iconRect;
  786.     char    oldMask[128], *mptr;
  787.     short    maskSize, i;
  788.  
  789.     if (!icon) return;
  790.  
  791.     mptr = (Ptr)(*icon)->iconMaskData;
  792.     iconRect = (*icon)->iconPMap.bounds;
  793.     maskSize = (iconRect.bottom - iconRect.top) * (*icon)->iconMask.rowBytes;
  794.     for (i = 0; i < maskSize; ++i) {
  795.         oldMask[i] = mptr[i];
  796.         mptr[i] = 0xFF;
  797.     }
  798.     DrawCIcon(icon, destRect);
  799.     mptr = (Ptr)(*icon)->iconMaskData;
  800.     for (i = 0; i < maskSize; ++i) mptr[i] = oldMask[i];
  801. }
  802.  
  803.  
  804.  
  805. /*****************************************************************************/
  806.  
  807.  
  808.  
  809. #pragma segment GWLayers
  810. void    DrawCIconByDepth(CIconHandle icon, Rect destRect, short depth, Boolean useMask)
  811. {
  812.     GrafPtr        curPort;
  813.     char        savedIconState;
  814.     char        savedDataState;
  815.     short        offset;
  816.     BitMapPtr    bmap;
  817.     Rect        iconRect;
  818.  
  819.     if (!icon) return;
  820.  
  821.     GetPort(&curPort);
  822.  
  823.     if (!depth) {
  824.         if (!(curPort->portBits.rowBytes & 0x8000))
  825.             depth = 1;
  826.         else
  827.             depth = (*(((CGrafPtr)curPort)->portPixMap))->pixelSize;
  828.     }
  829.  
  830.     savedIconState = HGetState((Handle)icon);        /* Lock down things. */
  831.     HLock((Handle)icon);
  832.     if (depth > 1) {
  833.         savedDataState = HGetState((*icon)->iconData);
  834.         HLock((*icon)->iconData);
  835.         (*icon)->iconPMap.baseAddr = *((*icon)->iconData);
  836.             /* Point the icon's pixMap at the color icon data. */
  837.     }
  838.  
  839.     iconRect = (*icon)->iconPMap.bounds;
  840.         /* Find out the dimensions of the icon. */
  841.  
  842.     (*icon)->iconMask.baseAddr = (Ptr)(*icon)->iconMaskData;
  843.         /* Point the mask's bitMap at the mask data. */
  844.  
  845.     offset  = iconRect.bottom - iconRect.top;
  846.     offset *= (*icon)->iconMask.rowBytes;
  847.     (*icon)->iconBMap.baseAddr = (*icon)->iconMask.baseAddr + offset;
  848.         /* Point the icon's bitMap at the b/w icon data. */
  849.  
  850.     bmap = (depth == 1) ? (BitMapPtr)&((*icon)->iconBMap) : (BitMapPtr)&((*icon)->iconPMap);
  851.     if (useMask)
  852.         CopyMask(bmap, &((*icon)->iconMask), &curPort->portBits, &iconRect, &iconRect, &destRect);
  853.     else
  854.         CopyBits(bmap, &curPort->portBits, &iconRect, &destRect, srcCopy, nil);
  855.  
  856.     HSetState((Handle)icon, savedIconState);        /* Unlock things. */
  857.     if (depth > 1)
  858.         HSetState((*icon)->iconData, savedDataState);
  859. }
  860.  
  861.  
  862.  
  863. /*****************************************************************************/
  864. /*****************************************************************************/
  865. /*****************************************************************************/
  866.  
  867.  
  868.  
  869. #pragma segment GWLayers
  870. static OSErr    DefaultLayerInit(LayerObj theLayer)
  871. {
  872.     LayerObj    aboveLayer;
  873.     GWorldPtr    layerWorld;        /* GWorld for this layer. */
  874.     Rect        parentRect;        /* Rectangle of parent in global coordinates. */
  875.     GrafPtr        parentPort;        /* Parent layer's GrafPort. */
  876.     GDHandle    parentGDevice;    /* Parent layer's GDevice. */
  877.     CGrafPtr    keepPort;        /* Saved GrafPort. */
  878.     GDHandle    keepGDevice;    /* Saved GDevice. */
  879.     Point        org;
  880.     OSErr        err;
  881.     short        depth;
  882.  
  883.     err = noErr;
  884.     if (theLayer) {
  885.         if (!(*theLayer)->layerPort) {
  886.  
  887.             aboveLayer = (*theLayer)->aboveLayer;
  888.             if (aboveLayer) {
  889.                 /* The default behavior is to create a GWorld the same size
  890.                 ** as the above layer, if there is one.  If there isn't an above
  891.                 ** layer and we were expected to create a GWorld, we have problems.
  892.                 ** This situation can't be resolved and is handled as a paramErr. */
  893.  
  894.                 if (!((*theLayer)->layerDepth))
  895.                     (*theLayer)->layerDepth = (*aboveLayer)->layerDepth;
  896.  
  897.                 SmartGetGWorld(&keepPort, &keepGDevice);        /* Keep the GWorld. */
  898.  
  899.                 parentPort    = (*aboveLayer)->layerPort;
  900.                 parentGDevice = (*aboveLayer)->layerGDevice;
  901.                     /* Grab the parent layer's GrafPort and GDevice. */
  902.     
  903.                 SmartSetGWorld((CGrafPtr)parentPort, parentGDevice);
  904.                 parentRect = GetEffectiveDstRect(aboveLayer);
  905.                     /* The default behavior is to use the portRect of the above
  906.                     ** port.  This behavior can be overridden if desired by setting
  907.                     ** dstRect.  dstRect is initialized to be empty, but if
  908.                     ** it is specifically set, then this layer should map into
  909.                     ** just the dstRect and not the portRect.  This is useful if
  910.                     ** the off-screen image is to be displayed in only a portion
  911.                     ** of a window. */
  912.  
  913.                 org.h = parentRect.left;
  914.                 org.v = parentRect.top;
  915.  
  916.                 LocalToGlobal(((Point *)&parentRect) + 0);
  917.                 LocalToGlobal(((Point *)&parentRect) + 1);
  918.                     /* Put the parent layer's destination rect in global coordinates. */
  919.     
  920.                 if (GetQDVersion())
  921.                     err = NewGWorld(&layerWorld, (*theLayer)->layerDepth, &parentRect, nil, nil, 0);
  922.                         /* Create the GWorld for this layer.  It will be created with the
  923.                         ** requested depth.  If the requested depth is 0, then it will be
  924.                         ** created with a depth great enough for the deepest monitor the
  925.                         ** parentRect intersects. */
  926.                 else
  927.                     err = MakeLayerWorld(&layerWorld, theLayer, parentRect);
  928.                         /* Create a bitmap for those systems without GWorlds. */
  929.  
  930.                 if (err == noErr) {
  931.                     (*theLayer)->layerOwnsPort = true;
  932.                     SetPort((*theLayer)->layerPort = (GrafPtr)layerWorld);
  933.                         /* Save the new GWorld in the layer object. */
  934.                     SetOrigin(org.h, org.v);
  935.                         /* Set the origin so that this GWorld maps directly into the
  936.                         ** area to be copied into (dstRect or portRect) for the
  937.                         ** above layer. */
  938.  
  939.                     if (!((*theLayer)->layerDepth)) {
  940.                         if (((GrafPtr)layerWorld)->portBits.rowBytes & 0x8000)
  941.                             depth = (*(((CGrafPtr)layerWorld)->portPixMap))->pixelSize;
  942.                         else
  943.                             depth = 1;
  944.                         (*theLayer)->layerDepth = depth;
  945.                     }
  946.                 }
  947.  
  948.                 SmartSetGWorld(keepPort, keepGDevice);        /* Restore the kept GWorld. */
  949.             }
  950.             else {
  951.                 err = paramErr;
  952.                     /* We were expected to create an off-screen GWorld of the
  953.                     ** same size as the above layer, but we didn't have an above
  954.                     ** layer.  This is an error.  The parameters passed to NewLayer
  955.                     ** were inappropriate for the situation, so return a paramErr. */
  956.             }
  957.         }
  958.     }
  959.  
  960.     return(err);
  961. }
  962.  
  963.  
  964.  
  965. /*****************************************************************************/
  966.  
  967.  
  968.  
  969. #pragma segment GWLayers
  970. static OSErr    DefaultLayerUpdate(LayerObj theLayer)
  971. {
  972.     LayerObj    belowLayer;
  973.     GrafPtr        belowPort, thisPort;
  974.     GDHandle    thisGDevice;
  975.     CGrafPtr    keepPort;
  976.     GDHandle    keepGDevice;
  977.     Rect        thisUpdate, belowRect, thisRect;
  978.     short        xfer;
  979.     RgnHandle    rgn;
  980.  
  981.     /* The default update behavior is to copy the area to be updated from the
  982.     ** below layer into the indicated layer.  We only need to update layer if
  983.     ** there is a below layer.  The bottom-most layer update doesn't do anything.
  984.     ** As a default, the bottom-most layer is considered background and does not
  985.     ** get updated. */
  986.  
  987.     if (theLayer) {
  988.         belowLayer = (*theLayer)->belowLayer;
  989.         if (belowLayer) {
  990.             /* Get this layer's GWorld and below layer's port. */
  991.             thisPort    = (*theLayer)->layerPort;
  992.             thisGDevice = (*theLayer)->layerGDevice;
  993.             belowPort   = (*belowLayer)->layerPort;
  994.  
  995.             /* Save current GWorld and set the parent's GWorld. */
  996.             SmartGetGWorld(&keepPort, &keepGDevice);
  997.             SmartSetGWorld((CGrafPtr)thisPort, thisGDevice);
  998.  
  999.             thisUpdate = UpdateUpdateRects(theLayer);
  1000.  
  1001.             rgn = NewRgn();
  1002.             RectRgn(rgn, &thisUpdate);
  1003.  
  1004.             belowRect = GetEffectiveSrcRect(belowLayer);
  1005.             thisRect  = GetEffectiveDstRect(theLayer);
  1006.  
  1007.                 /* As a default behavior, we CopyBits the below layer into this layer. */
  1008.             LockLayerWorld(belowLayer);
  1009.             LockLayerWorld(theLayer);
  1010.             xfer = (*theLayer)->xferMode;
  1011.             CopyBits(&belowPort->portBits, &thisPort->portBits, &belowRect, &thisRect, xfer, rgn);
  1012.             UnlockLayerWorld(theLayer);
  1013.             UnlockLayerWorld(belowLayer);
  1014.             DisposeRgn(rgn);
  1015.  
  1016.             SmartSetGWorld(keepPort, keepGDevice);        /* Restore to the kept GWorld. */
  1017.         }
  1018.     }
  1019.     return(noErr);
  1020. }
  1021.  
  1022.  
  1023.  
  1024. /*****************************************************************************/
  1025.  
  1026.  
  1027.  
  1028. #pragma segment GWLayers
  1029. static OSErr    DefaultLayerDispose(LayerObj theLayer)
  1030. {
  1031.     GWorldPtr    theWorld;
  1032.  
  1033.     if (theLayer) {
  1034.         if ((*theLayer)->layerOwnsPort) {
  1035.             theWorld = (GWorldPtr)(*theLayer)->layerPort;
  1036.             if (theWorld) {
  1037.                 if ((*theLayer)->layerBitmap)
  1038.                     KillLayerWorld(theLayer);
  1039.                 else
  1040.                     DisposeGWorld(theWorld);
  1041.             }
  1042.         }
  1043.     }
  1044.  
  1045.     return(noErr);
  1046. }
  1047.  
  1048.  
  1049.  
  1050. /*****************************************************************************/
  1051.  
  1052.  
  1053.  
  1054. #pragma segment GWLayers
  1055. static OSErr    MakeLayerWorld(GWorldPtr *layerWorld, LayerObj theLayer, Rect bnds)
  1056. {
  1057.     GrafPtr    oldPort;
  1058.     GrafPtr    newPort;
  1059.     Handle    bitmap;
  1060.     OSErr    err;
  1061.  
  1062.     OffsetRect(&bnds, -bnds.left, -bnds.top);    /* Make sure upper-left is 0,0. */
  1063.  
  1064.     GetPort(&oldPort);        /* Need this to restore the port after OpenPort. */
  1065.  
  1066.     newPort = (GrafPtr)NewPtr(sizeof(GrafPort));        /* Allocate the grafPort. */
  1067.     err = MemError();
  1068.     if (err)
  1069.         return(err);        /* Failed to allocate the off-screen port. */
  1070.  
  1071.     /* The call to OpenPort does the following:
  1072.     ** 1) allocates space for visRgn (set to screenBits.bounds) and clipRgn (set wide open)
  1073.     ** 2) sets portBits to screenBits
  1074.     ** 3) sets portRect to screenBits.bounds, etc. (see IM I-163,164)
  1075.     ** 4) side effect: does a SetPort(&offScreen) */
  1076.  
  1077.     OpenPort(newPort);
  1078.     SetPort(oldPort);
  1079.  
  1080.         /* Now make bitmap the size of the bounds that caller supplied. */
  1081.  
  1082.     newPort->portRect = bnds;
  1083.     newPort->portBits.bounds = bnds;
  1084.     RectRgn(newPort->visRgn, &bnds);
  1085.  
  1086.     SetRectRgn(newPort->clipRgn, -32000, -32000, 32000, 32000);
  1087.         /* Avoid wide-open clipRgn, to be safe.    */
  1088.  
  1089.     /* rowBytes is size of row, it must be rounded up to an even number of bytes. */
  1090.     newPort->portBits.rowBytes = ((bnds.right - bnds.left + 15) >> 4) << 1;
  1091.  
  1092.     bitmap = NewHandle(newPort->portBits.rowBytes * (long)(bnds.bottom - bnds.top));
  1093.     err = MemError();
  1094.     if (err) {
  1095.         ClosePort(newPort);            /* Dump the visRgn and clipRgn. */
  1096.         DisposePtr((Ptr)newPort);    /* Dump the GrafPort. */
  1097.         return(err);
  1098.     }
  1099.  
  1100.     (*theLayer)->layerBitmap = bitmap;
  1101.     *layerWorld              = (GWorldPtr)newPort;
  1102.  
  1103.     return(noErr);
  1104. }
  1105.  
  1106.  
  1107.  
  1108. /*****************************************************************************/
  1109.  
  1110.  
  1111.  
  1112. #pragma segment GWLayers
  1113. static void    KillLayerWorld(LayerObj theLayer)
  1114. {
  1115.     DisposeHandle((*theLayer)->layerBitmap);
  1116.     (*theLayer)->layerBitmap = nil;
  1117.  
  1118.     ClosePort((*theLayer)->layerPort);
  1119.     DisposePtr((Ptr)(*theLayer)->layerPort);
  1120.     (*theLayer)->layerPort = nil;
  1121. }
  1122.  
  1123.  
  1124.  
  1125.  
  1126. /*****************************************************************************/
  1127.  
  1128.  
  1129.  
  1130. #pragma segment GWLayers
  1131. static void    SmartGetGWorld(CGrafPtr *port, GDHandle *gdh)
  1132. {
  1133.     if (GetQDVersion())
  1134.         GetGWorld(port, gdh);
  1135.     else {
  1136.         *gdh = nil;
  1137.         GetPort((GrafPtr *)port);
  1138.     }
  1139. }
  1140.  
  1141.  
  1142.  
  1143. /*****************************************************************************/
  1144.  
  1145.  
  1146.  
  1147. #pragma segment GWLayers
  1148. static void    SmartSetGWorld(CGrafPtr port, GDHandle gdh)
  1149. {
  1150.     if (GetQDVersion())
  1151.         SetGWorld(port, gdh);
  1152.     else
  1153.         SetPort((GrafPtr)port);
  1154. }
  1155.  
  1156.  
  1157.  
  1158. /*****************************************************************************/
  1159.  
  1160.  
  1161.  
  1162. #pragma segment GWLayers
  1163. static short    GetQDVersion()
  1164. {
  1165.     long    gestaltResult;
  1166.  
  1167.     if (Gestalt(gestaltQuickdrawVersion, &gestaltResult))
  1168.         gestaltResult = 0;
  1169.  
  1170.     return((gestaltResult >> 8) & 0xFF);
  1171. }
  1172.  
  1173.  
  1174.  
  1175.